/*
 * GeoVISTA Center (Penn State, Dept. of Geography)
 * Copyright (c), 2003-2011,  Jin Chen and Alan M. MacEachren, GeoVISTA Center, Penn State University
 * Licensed under Simplified BSD License
 *
 *
 * @author: jin Chen 
 * @date: May 23, 2005$
 * @version: 1.0
 */
package edu.psu.geovista.app.hce.clustering.similarity.attribute;

import java.util.Vector;

public class EuclideanSimilarity extends BasicSimilarity {
    /*******************************************************************************************************
     *                vector
     *******************************************************************************************************/
   /**
    *
     * @param attrs1   Float vector
    * @param attrs2
    * @param weights    attribute weights , by default can set it =null
    * @return
    */
   public  double similarity(Vector attrs1, Vector  attrs2, Vector  weights) {
        if(attrs1==null||attrs2==null||( attrs1.size() !=attrs2.size() )){
           new IllegalArgumentException( " is passed 2 Map with different size.");
        }
        double similarity=0.0;
        int size = attrs1.size();
        if(size==0)return 0;


       //float[] attrvalues1 = CollectionUtils.convertVectorToFloat(attrs1);
       //float[] attrvalues2 = CollectionUtils.convertVectorToFloat(attrs2);

       double sum = 0.0;
       int counter = 0;
       for (int i = 0; i < size; i++) {

            float v1 = ((Float)attrs1.get(i)).floatValue() ;  //attrvalues1[i];//
            float v2 = ((Float)attrs2.get(i)).floatValue() ;//attrvalues2[2]; //


            if((!Float.isNaN(v1))&&(!Float.isNaN(v2))) {
                float weight = getWeight(weights, i);

                sum = sum + weight * (v1 - v2) * (v1 - v2);
                counter++;
            }

        }

        double d = Math.sqrt(sum);

        if(counter > 0)
            return convert2Similarity(d);
        else
            return Double.NaN;

    }

    /*******************************************************************************************************
     *                float[]
     *******************************************************************************************************/

   /**
    *
     * @param attrs1   Float vector
    * @param attrs2
    * @param weights    attribute weights . If null, means equal weights
    * @return
    */
   public  double similarity(float[] attrs1, float[] attrs2, float[] weights) {
        if(attrs1==null||attrs2==null||( attrs1.length !=attrs2.length  )){
           new IllegalArgumentException(" is passed 2 data arrays with different size.");
        }
        double similarity=Double.NaN;
        int size = attrs1.length;
        if(size==0)return 0;



       double sum = 0.0;
       int counter = 0;
       for (int i = 0; i < size; i++) {

            float v1 = attrs1[i] ;
            float v2 = attrs2[i] ;


            if((!Float.isNaN(v1))&&(!Float.isNaN(v2))) {
                float weight = getWeight(weights, i);

                sum = sum + weight * (v1 - v2) * (v1 - v2);
                counter++;
            }

        }

        double d = Math.sqrt(sum/size);// divided by size to normalize

        if(counter > 0)
            similarity=1-d;//1-d;//1-d*d;//Math.sqrt(1-d*d);//1-d;//(1 - (d / (1 + d)));
       return similarity;


    }

    /*******************************************************************************************************
     *                double
     *******************************************************************************************************/
    /**
    *
     * @param attrs1   Float vector
    * @param attrs2
    * @param weights    attribute weights . If null, means equal weights
    * @return
    */
   public  double similarity(double[] attrs1, double[] attrs2, double[] weights) {
        if(attrs1==null||attrs2==null||( attrs1.length !=attrs2.length  )){
           new IllegalArgumentException(" is passed 2 data arrays with different size.");
        }
        double similarity=Double.NaN;
        int size = attrs1.length;
        if(size==0)return 0;



       double sum = 0.0;
       int counter = 0;
       for (int i = 0; i < size; i++) {

            double v1 = attrs1[i] ;
            double v2 = attrs2[i] ;


            if((!Double.isNaN(v1))&&(!Double.isNaN(v2))) {
                double weight = getWeight(weights, i);

                sum = sum + weight * (v1 - v2) * (v1 - v2);
                counter++;
            }

        }

        double d = Math.sqrt(sum/size);// divided by size to normalize

        if(counter > 0)
            similarity=1-d;//1-d;//1-d*d;//Math.sqrt(1-d*d);//1-d;//(1 - (d / (1 + d)));
        if(similarity<0){
            System.out.println("");
        }
        return similarity;


    }

}
